#import "CFWireFrame.h"

@implementation CFWireFrame:Object


// this code is copyright Darcy Brockbank, 1993
//
// You may freely reuse and distribute this code in any way shape or
// form, provided that this notice stays intact.
//
// darcy@hasc.ca, samurai@cs.mcgill.ca
//
// StefView was implemented out of WorldSpaceView and retains some of the
// movement properties...
//
// The code for WorldSpaceView was written by Sam Streeper at CreepyFace, I think,
// and there were two other contributors, but I can't find their names in the
// source for it.
//
// CreepyFaceView shows a simple (ha!) spinning CreepyFace logo, in full 3D. The 3D code
// came from an app I wrote a long time ago called "CFWireFrame", and so the code
// is pretty scary. As well, this thing is only a quick hack, though a nice one.
//
// This thing has room for improvement, and if you do so, send me a copy!
//
// - darcy

#define SCALE 1.0045

- getCentre:(float*) x:(float *)y :(float *)z
{
	*x=myCentre.x;
	*y=myCentre.y;
	*z=myCentre.z;
	return self;
}

- getFrameColour:(float *)r :(float *)g :(float *)b
{
	*r=myFrameColour.red;
	*b=myFrameColour.blue;
	*g=myFrameColour.green;
	return self;
}

- getTagColour:(float *)r :(float *)g :(float *)b
{
	*r=myTagColour.red;
	*b=myTagColour.blue;
	*g=myTagColour.green;
	return self;
}


static int count(const char *s,char thisChar)
{
	int c=0;
	
	for (;*s!=(char)0;s++)	if (*s==thisChar) c++;
	return (c);
}

#define LIM 6400000.0

- init
{
	[super init];
	myLineWidth=0.1;
	psint=sin(0.085);
	nsint=-psint;
	cost=cos(0.085);
 	bbox[0]=-LIM;
	bbox[1]=-LIM;
	bbox[2]=2*LIM;
	bbox[3]=2*LIM;
	myTable = [[NXStringTable alloc] init];
	dimension=4;
	return self;
}

- free
{
	[myTable free];
	return [super free];
}

- addMyPS:(char)command
{
	myPSCommands[numberOfMyPS++]=command;
	return self;
}

- addPoint:(float)x :(float)y :(float)z
{
	myCoords[numberOfCoords*4]=x;
	myCoords[numberOfCoords*4+1]=y;
	myCoords[numberOfCoords*4+2]=z;
	myCoords[numberOfCoords*4+3]=1.0;
	numberOfCoords++;
	return self;
}
	
- moveTo:(float)x:(float)y:(float)z
{
	int i;
	
	for(i=0;i<numberOfCoords*dimension;i+=dimension){
		myCoords[i]+=(x-myCentre.x);
		myCoords[i+1]+=(y-myCentre.y);
		myCoords[i+2]+=(z-myCentre.z);
	}
	for(i=0;i<numberOfTags*coordsInATag*dimension;i+=dimension){
		myTags[i]+=(x-myCentre.x);
		myTags[i+1]+=(y-myCentre.y);
		myTags[i+2]+=(z-myCentre.z);
	}
	myCentre.x=x;
	myCentre.y=y;
	myCentre.z=z;
	return self;
}


- drawYourself:(float)zoom centeredOn:(float)X :(float)Y;
{
	int i,j,x;
	int stop,start;
	BOOL behindMe;
	DPSUserPathAction op;

	behindMe=NO;
	stop=numberOfCoords*dimension;
	for (i=0,j=0;i<stop;j+=2,i+=dimension){
		if (myCoords[i+2]>=-0.001) {
			behindMe=YES;
			break;
		}
		output[j]=((myCoords[i])*(-zoom/myCoords[i+2]))+X;
		output[j+1]=((myCoords[i+1])*(-zoom/myCoords[i+2]))+Y;
	}
	if (!behindMe && stop!=0 && numberOfCoords>0){
			PSsetrgbcolor(myFrameColour.red,myFrameColour.green,myFrameColour.blue);
			DPSDoUserPath(output,2*numberOfCoords,dps_float,myPSCommands,
			numberOfMyPS,bbox,dps_ustroke);
	}
	if (numberOfTags){
		op=dps_ufill;
		for(x=0;x<numberOfTags;x++){
			behindMe=NO;
			start=x*coordsInATag*dimension;
			if (!(myTags[2+start]>=myCentre.z)) { // closer than centre
				op = dps_ustroke;
			}
			stop=start+(coordsInATag*dimension);
			for(j=0,i=start;i<stop;j+=2,i+=dimension){
				if (myTags[i+2]>=0){
					 behindMe=YES;
					 break;
				}
				output[j]=((myTags[i])*(-zoom/myTags[i+2]))+X;
				output[j+1]=((myTags[i+1])*(-zoom/myTags[i+2]))+Y;
			}
			if (!behindMe && coordsInATag > 0){
				PSsetrgbcolor(myTagColour.red,myTagColour.green,myTagColour.blue) ;
				DPSDoUserPath(output,(2*coordsInATag),dps_float,myTagPSCommands,
					numberOfTagPS,bbox,op);
			}
		}
	}
	return self;
}		

- rotate: (Direction) direction aroundAxis:(Axis) thisAxis atOrigin:(Origin) thisOrigin	
{
	double mysint;
	double s1,s2,s3;
	Origin origin;
	int i;

	if (direction==negative) {
		mysint=nsint;
	}
	else {
		mysint=psint;
	}

	origin=thisOrigin;
	switch(thisAxis){
	case x:
		for (i=0;i<numberOfCoords*dimension;i+=dimension){
			s2=myCoords[i+1]-origin.y;
			s3=myCoords[i+2]-origin.z;
			myCoords[i+1]=(float)((s2)*cost-(s3)*mysint)+origin.y;
			myCoords[i+2]=(float)((s2)*mysint+(s3)*cost)+origin.z;
		}
		for (i=0; i<(numberOfTags*coordsInATag)*dimension; i+=dimension){
			s2=myTags[i+1]-origin.y;
			s3=myTags[i+2]-origin.z;
			myTags[i+1]=(float)((s2)*cost-(s3)*mysint)+origin.y;
			myTags[i+2]=(float)((s2)*mysint+(s3)*cost)+origin.z;
		}
		s2=myCentre.y-origin.y;
		s3=myCentre.z-origin.z;
		myCentre.y=(float)(s2*cost-s3*mysint)+origin.y;
		myCentre.z=(float)(s2*mysint+s3*cost)+origin.z;
		break;
	case y:
		for (i=0; i<numberOfCoords*dimension; i+=dimension){
			s1=myCoords[i]-origin.x;
			s3=myCoords[i+2]-origin.z;
			myCoords[i]=(float)((s1)*cost+s3*mysint)+origin.x;
			myCoords[i+2]=(float)((-s1)*mysint+s3*cost)+origin.z;
		}	
		for (i=0; i<(numberOfTags*coordsInATag*dimension); i+=dimension){
			s1=myTags[i]-origin.x;
			s3=myTags[i+2]-origin.z;
			myTags[i]=(float)((s1)*cost+s3*mysint)+origin.x;
			myTags[i+2]=(float)((-s1)*mysint+s3*cost)+origin.z;
		}	
		s1=myCentre.x-origin.x;
		s3=myCentre.z-origin.z;
		myCentre.x=(float)(s1*cost+s3*mysint)+origin.x;
		myCentre.z=(float)(-s1*mysint+s3*cost)+origin.z;
		break;
	case z:
		for (i=0; i<numberOfCoords*dimension; i+=dimension){
			s1=myCoords[i]-origin.x;
			s2=myCoords[i+1]-origin.y;
			myCoords[i]=(float)(s1*cost-s2*mysint)+origin.x;
			myCoords[i+1]=(float)(s1*mysint+s2*cost)+origin.y;
		}
		for (i=0; i<(numberOfTags*coordsInATag*dimension); i+=dimension){
			s1=myTags[i]-origin.x;
			s2=myTags[i+1]-origin.y;
			myTags[i]=(float)(s1*cost-s2*mysint)+origin.x;
			myTags[i+1]=(float)(s1*mysint+s2*cost)+origin.y;
		}
		s2=myCentre.y-origin.x;
		s1=myCentre.x-origin.y;
		myCentre.x=(float)(s1*cost-s2*mysint)+origin.x;
		myCentre.y=(float)(s1*mysint+s2*cost)+origin.y;
	}
	return self;
}
	
- translate: (Direction) direction alongAxis: (Axis) thisAxis atRate:(float) rate
{
	float mydir;
	int i;
	
	if(direction==negative) {
		mydir=-1*rate;
	}
	else {
		mydir=rate;
	}
	
	switch(thisAxis) {
	case x:
		myCentre.x+=mydir;
		break;
	case y:
		myCentre.y+=mydir;
		break;
	case z:
		myCentre.z+=mydir;
		break;
	}		
	for(i=0;i<numberOfCoords*dimension;i+=dimension){
		myCoords[i+thisAxis]+=mydir;
	}
	for(i=0;i<numberOfTags*coordsInATag*dimension;i+=dimension){
		myTags[i+thisAxis]+=mydir;
	}
	return self;
}			
	


- setCentre:(float) x :(float)y :(float)z
{
	printf("Setting\n");
	myCentre.x=x;
	myCentre.y=y;
	myCentre.z=z;
	return self;
}

- setFrameColour:(float) r :(float)g :(float)b
{
	myFrameColour.red=r;
	myFrameColour.green=g;
	myFrameColour.blue=b;
	return self;
}

- setTagColour:(float) r :(float)g :(float)b
{
	myTagColour.red=r;
	myTagColour.green=g;
	myTagColour.blue=b;
	return self;
}	

- setNumberOfTags:(int)count
{
	numberOfTags=count;
	return self;
}

- setCoordsInATag:(int)count;
{
	coordsInATag=count;
	return self;
}

- setNumberOfTagPS:(int)count;
{
	numberOfTagPS=count;
	return self;
}

- setNumberOfCoords:(int) count;
{
	numberOfCoords=count;
	return self;
}

- setNumberOfMyPS:(int) count;
{
	numberOfMyPS=count;
	return self;
}

- setBoundingBox:(float *) thisBox
{
	bbox[0]=-1.0e16;
	bbox[1]=-1.0e16;
	bbox[2]=1.0e16;
	bbox[3]=1.0e16;
	
	return self;
}

- (int) getNumberOfMyPS
{
	return  numberOfMyPS;
}

- (int) getNumberOfPoints
{
	return (numberOfCoords);
}

- makeCFWireFrame:(const char *)thisFrame
{
	const char *frameCoords,*framePS,*tagCoords,*numOfTags,*frameColour,
		*frameCentre,*tagColour,*tagPS, *coordsInTag,*check;
	int i;
	char ps=0;
	
	
	if ([myTable readFromFile:thisFrame]==nil){
		return self;
		NXRunAlertPanel(thisFrame,"The file is not in the given directory. Please fix this problem and restart the application.","Quit",NULL,NULL);
		[NXApp terminate:self];
	}


	
	frameCoords=[myTable valueForStringKey:"FramePoints"];
	tagCoords=[myTable valueForStringKey:"TagPoints"];
	frameColour=[myTable valueForStringKey:"FrameColor"];
	tagColour=[myTable valueForStringKey:"TagColor"];
	framePS=[myTable valueForStringKey:"FramePS"];
	coordsInTag=[myTable valueForStringKey:"PointsPerTag"];
	numOfTags=[myTable valueForStringKey:"NumberOfTags"];
	frameCentre=[myTable valueForStringKey:"FrameCenter"];
	tagPS=[myTable valueForStringKey:"TagPS"];
	
	numberOfTags=atoi(numOfTags);
	coordsInATag=atoi(coordsInTag);
	numberOfCoords=count(frameCoords,',')+1;

	numberOfMyPS=count(framePS,',')+1;
	numberOfTagPS=count(tagPS,',')+1;
	
	sscanf(frameColour,"%f , %f , %f",
		&myFrameColour.red,&myFrameColour.green,&myFrameColour.blue);
	sscanf(tagColour,"%f , %f , %f",
		&myTagColour.red,&myTagColour.green,&myTagColour.blue);
	
	sscanf(frameCentre,"%f , %f , %f",&myCentre.x,&myCentre.y,&myCentre.z);
	
	for(i=0,check=framePS;check!=(char *)1;i++,check=index(check,',')+1){
		switch(check[0]){
		case 'a':	
			switch (check[3]){
			case 'n':	ps=dps_arcn; break;
			case 't':	ps=dps_arct; break;
			default:	ps=dps_arc;
			}
			break;
		case 'm':	ps=dps_moveto;break;
		case 'r':	
			switch(check[1]){ 
			case 'm':	ps=dps_rmoveto;break;
			case 'l':	ps=dps_rlineto;	break;
			default:	ps=dps_rcurveto;
			}
			break;
			switch(check[1]){
			case 'l' :ps=dps_closepath;	break;
			case 'u':ps=dps_curveto;	break;
			}
		case 'c':	
			switch(check[1]){
			case 'l' :ps=dps_closepath;	break;
			case 'u':ps=dps_curveto;	break;
			}
			break;
		case 'u':	ps=dps_ucache; break;
		case 'l' : 	ps=dps_lineto;	break;
		default:	ps=-1;
		}
		myPSCommands[i]=ps;
	}	

	for(i=0,check=tagPS;check!=(char *)1;i++,check=index(check,',')+1){
		switch(check[0]){
		case 'a':
			switch (check[3]){
			case 'n':	ps=dps_arcn;	break;
			case 't':	ps=dps_arct;	break;
			default:	ps=dps_arc;
			}
			break;
		case 'm':	ps=dps_moveto;	break;
		case 'r':
			switch(check[1]){
			case 'm':	ps=dps_rmoveto; break;
			case 'l':	ps=dps_rlineto; 	break;
			default:	ps=dps_rcurveto;
			}
			break;
		case 'c':	
			switch(check[1]){
			case 'l' :ps=dps_closepath;	break;
			case 'u':ps=dps_curveto;	break;
			}
			break;
		case 'u':	ps=dps_ucache;	break;
		case 'l' : 	ps=dps_lineto;	break;
		default:	ps=-1;	break;
		}
		myTagPSCommands[i]=ps;
	}	
	
	for (i=0,check=frameCoords;i<numberOfCoords;i++,check=(index(check,',')+1)){
		sscanf(check," %f",(&myCoords[i]));
	}
	for (i=0,check=tagCoords;i<numberOfTags*coordsInATag*4;i++,check=(index(check,',')+1)){
		sscanf(check," %f",(&myTags[i]));
	}
	numberOfCoords/=4;

	return self;
}

- readBinaryCodeFrom: (char *) thisFile
{
	return self;
}

	
	
	
	
	

@end
